//
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import XCTest

@testable import SignalServiceKit

final class TSOutgoingMessageRecipientStateTest: XCTestCase {
    func testStableDecoding() throws {
        struct TestCase {
            let data: Data
            let assertions: (TSOutgoingMessageRecipientState) -> Void
        }

        /// Data generated via `testGenerateData` below.
        let testCases: [TestCase] = [
            TestCase(
                data: .data(fromHex: "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001a60b0c1718191a55246e756c6cd50d0e0f101112131414165624636c617373596572726f72436f64655573746174655f100f4d544c4d6f64656c56657273696f6e5b77617353656e7442795544800580038002800280041000100c08d21b1c1d1e5a24636c6173736e616d655824636c61737365735f101f54534f7574676f696e674d657373616765526563697069656e745374617465a31f20215f101f54534f7574676f696e674d657373616765526563697069656e745374617465584d544c4d6f64656c584e534f626a65637400080011001a00240029003200370049004c00510053005a0060006b0072007c0082009400a000a200a400a600a800aa00ac00ae00af00b400bf00c800ea00ee011001190000000000000201000000000000002200000000000000000000000000000122")!,
                assertions: { state in
                    XCTAssertEqual(state.status, .failed)
                    XCTAssertEqual(state.errorCode, 12)
                }
            ),
            TestCase(
                data: .data(fromHex: "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001a60b0c1516171855246e756c6cd40d0e0f10111213145624636c6173735573746174655f100f4d544c4d6f64656c56657273696f6e5b77617353656e744279554480058003800280041000100108d2191a1b1c5a24636c6173736e616d655824636c61737365735f101f54534f7574676f696e674d657373616765526563697069656e745374617465a31d1e1f5f101f54534f7574676f696e674d657373616765526563697069656e745374617465584d544c4d6f64656c584e534f626a65637400080011001a00240029003200370049004c00510053005a00600069007000760088009400960098009a009c009e00a000a100a600b100ba00dc00e00102010b0000000000000201000000000000002000000000000000000000000000000114")!,
                assertions: { state in
                    XCTAssertEqual(state.status, .sending)
                }
            ),
            TestCase(
                data: .data(fromHex: "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001a60b0c1516171855246e756c6cd40d0e0f10111213145624636c6173735573746174655f100f4d544c4d6f64656c56657273696f6e5b77617353656e744279554480058003800280041000100208d2191a1b1c5a24636c6173736e616d655824636c61737365735f101f54534f7574676f696e674d657373616765526563697069656e745374617465a31d1e1f5f101f54534f7574676f696e674d657373616765526563697069656e745374617465584d544c4d6f64656c584e534f626a65637400080011001a00240029003200370049004c00510053005a00600069007000760088009400960098009a009c009e00a000a100a600b100ba00dc00e00102010b0000000000000201000000000000002000000000000000000000000000000114")!,
                assertions: { state in
                    XCTAssertEqual(state.status, .skipped)
                }
            ),
            TestCase(
                data: .data(fromHex: "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001a60b0c1516171855246e756c6cd40d0e0f10111213145624636c6173735573746174655f100f4d544c4d6f64656c56657273696f6e5b77617353656e744279554480058003800280041000100309d2191a1b1c5a24636c6173736e616d655824636c61737365735f101f54534f7574676f696e674d657373616765526563697069656e745374617465a31d1e1f5f101f54534f7574676f696e674d657373616765526563697069656e745374617465584d544c4d6f64656c584e534f626a65637400080011001a00240029003200370049004c00510053005a00600069007000760088009400960098009a009c009e00a000a100a600b100ba00dc00e00102010b0000000000000201000000000000002000000000000000000000000000000114")!,
                assertions: { state in
                    XCTAssertEqual(state.status, .sent)
                    XCTAssertTrue(state.wasSentByUD)
                }
            ),
            TestCase(
                data: .data(fromHex: "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001a70b0c1718191a1b55246e756c6cd50d0e0f101112131415165624636c6173735573746174655f101164656c697665727954696d657374616d705f100f4d544c4d6f64656c56657273696f6e5b77617353656e74427955448006800380048002800510001003101709d21c1d1e1f5a24636c6173736e616d655824636c61737365735f101f54534f7574676f696e674d657373616765526563697069656e745374617465a32021225f101f54534f7574676f696e674d657373616765526563697069656e745374617465584d544c4d6f64656c584e534f626a65637400080011001a00240029003200370049004c00510053005b0061006c00730079008d009f00ab00ad00af00b100b300b500b700b900bb00bc00c100cc00d500f700fb011d0126000000000000020100000000000000230000000000000000000000000000012f")!,
                assertions: { state in
                    XCTAssertEqual(state.status, .delivered)
                    XCTAssertEqual(state.statusTimestamp, 23)
                    XCTAssertTrue(state.wasSentByUD)
                }
            ),
            TestCase(
                data: .data(fromHex: "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001a80b0c191a1b1c1d1e55246e756c6cd60d0e0f1011121314151617185d7265616454696d657374616d705624636c6173735573746174655f101164656c697665727954696d657374616d705f100f4d544c4d6f64656c56657273696f6e5b77617353656e7442795544800380078004800580028006100010171003101609d21f2021225a24636c6173736e616d655824636c61737365735f101f54534f7574676f696e674d657373616765526563697069656e745374617465a32324255f101f54534f7574676f696e674d657373616765526563697069656e745374617465584d544c4d6f64656c584e534f626a65637400080011001a00240029003200370049004c00510053005c0062006f007d0084008a009e00b000bc00be00c000c200c400c600c800ca00cc00ce00d000d100d600e100ea010c01100132013b0000000000000201000000000000002600000000000000000000000000000144")!,
                assertions: { state in
                    XCTAssertEqual(state.status, .read)
                    XCTAssertEqual(state.statusTimestamp, 23)
                    XCTAssertTrue(state.wasSentByUD)
                }
            ),
            TestCase(
                data: .data(fromHex: "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001a90b0c1b1c1d1e1f202155246e756c6cd70d0e0f101112131415161718191a5624636c6173735f100f76696577656454696d657374616d705f100f4d544c4d6f64656c56657273696f6e5d7265616454696d657374616d705f101164656c697665727954696d657374616d705573746174655b77617353656e744279554480088006800280038005800480071000101610031015101709d2222324255a24636c6173736e616d655824636c61737365735f101f54534f7574676f696e674d657373616765526563697069656e745374617465a32627285f101f54534f7574676f696e674d657373616765526563697069656e745374617465584d544c4d6f64656c584e534f626a65637400080011001a00240029003200370049004c00510053005d006300720079008b009d00ab00bf00c500d100d300d500d700d900db00dd00df00e100e300e500e700e900ea00ef00fa010301250129014b0154000000000000020100000000000000290000000000000000000000000000015d")!,
                assertions: { state in
                    XCTAssertEqual(state.status, .viewed)
                    XCTAssertEqual(state.statusTimestamp, 23)
                    XCTAssertTrue(state.wasSentByUD)
                }
            ),
            TestCase(
                data: .data(fromHex: "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001a80b0c191a1b1c1d1e55246e756c6cd60d0e0f1011121314151617185624636c6173735573746174655f101164656c697665727954696d657374616d705f100f4d544c4d6f64656c56657273696f6e5f100f76696577656454696d657374616d705b77617353656e7442795544800780038004800280058006100010031016101709d21f2021225a24636c6173736e616d655824636c61737365735f101f54534f7574676f696e674d657373616765526563697069656e745374617465a32324255f101f54534f7574676f696e674d657373616765526563697069656e745374617465584d544c4d6f64656c584e534f626a65637400080011001a00240029003200370049004c00510053005c0062006f0076007c009000a200b400c000c200c400c600c800ca00cc00ce00d000d200d400d500da00e500ee011001140136013f0000000000000201000000000000002600000000000000000000000000000148")!,
                assertions: { state in
                    XCTAssertEqual(state.status, .viewed)
                    XCTAssertEqual(state.statusTimestamp, 23)
                    XCTAssertTrue(state.wasSentByUD)
                }
            ),
            TestCase(
                data: .data(fromHex: "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001a60b0c1516171855246e756c6cd40d0e0f10111213145624636c6173735573746174655f100f4d544c4d6f64656c56657273696f6e5b77617353656e744279554480058003800280041000100408d2191a1b1c5a24636c6173736e616d655824636c61737365735f101f54534f7574676f696e674d657373616765526563697069656e745374617465a31d1e1f5f101f54534f7574676f696e674d657373616765526563697069656e745374617465584d544c4d6f64656c584e534f626a65637400080011001a00240029003200370049004c00510053005a00600069007000760088009400960098009a009c009e00a000a100a600b100ba00dc00e00102010b0000000000000201000000000000002000000000000000000000000000000114")!,
                assertions: { state in
                    XCTAssertEqual(state.status, .pending)
                }
            ),
        ]

        for (idx, testCase) in testCases.enumerated() {
            let state = try NSKeyedUnarchiver.unarchivedObject(
                ofClass: TSOutgoingMessageRecipientState.self,
                from: testCase.data,
                requiringSecureCoding: false
            )

            guard let state else {
                XCTFail("Failed to decode test case \(idx)!")
                continue
            }

            testCase.assertions(state)
        }
    }

    /*
    /// Generate hex data for stable-decoding test fixtures. Preserved here for
    /// historical reference, but not expected to continue to compile as the
    /// model changes.
    func testGenerateData() {
        let states: [TSOutgoingMessageRecipientState] = [
            {
                let state = TSOutgoingMessageRecipientState()!
                state.state = .failed
                state.errorCode = NSNumber(value: 12)
                return state
            }(),
            {
                let state = TSOutgoingMessageRecipientState()!
                state.state = .sending
                return state
            }(),
            {
                let state = TSOutgoingMessageRecipientState()!
                state.state = .skipped
                return state
            }(),
            {
                let state = TSOutgoingMessageRecipientState()!
                state.state = .sent
                state.wasSentByUD = true
                return state
            }(),
            {
                let state = TSOutgoingMessageRecipientState()!
                state.state = .sent
                state.wasSentByUD = true
                state.deliveryTimestamp = NSNumber(value: 23)
                return state
            }(),
            {
                let state = TSOutgoingMessageRecipientState()!
                state.state = .sent
                state.wasSentByUD = true
                state.deliveryTimestamp = NSNumber(value: 22)
                state.readTimestamp = NSNumber(value: 23)
                return state
            }(),
            {
                let state = TSOutgoingMessageRecipientState()!
                state.state = .sent
                state.wasSentByUD = true
                state.deliveryTimestamp = NSNumber(value: 21)
                state.readTimestamp = NSNumber(value: 22)
                state.viewedTimestamp = NSNumber(value: 23)
                return state
            }(),
            {
                let state = TSOutgoingMessageRecipientState()!
                state.state = .sent
                state.wasSentByUD = true
                state.deliveryTimestamp = NSNumber(value: 22)
                state.viewedTimestamp = NSNumber(value: 23)
                return state
            }(),
            {
                let state = TSOutgoingMessageRecipientState()!
                state.state = .pending
                return state
            }(),
        ]

        for (idx, state) in states.enumerated() {
            let data = try! NSKeyedArchiver.archivedData(
                withRootObject: state,
                requiringSecureCoding: false
            )

            print("\(idx): \(data.hexadecimalString)")
        }
    }
     */
}
